home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / LIBRARY / FUTILS / FWIN.DOC < prev    next >
Text File  |  1989-02-21  |  11KB  |  268 lines

  1.                              /\ RKCP /\
  2.                              \/ RKCP \/
  3.  
  4. ********************************************************************
  5. ************************* FWIN by Rex Kerr *************************
  6. ************************ Copyright (C) 1989 ************************
  7. ********************************************************************
  8.  
  9. This is a unit designed to give simple windowing capabilities to
  10. any program.  It uses FWRITE, so it is very fast, but it also
  11. causes snow on snowy CGAs.  It also won't autodetect EGA or VGA
  12. cards (another weakness of FWRITE).  On top of all that, if you
  13. call windows in circles (i.e. you call window #1, then #2, #3, #1,
  14. #2, etc.) and then delete one, the image will be left on the screen,
  15. even though the window itself is gone.  By now, I've made it sound
  16. horrible enough for no-one to want to use it.  But it is very fast,
  17. and it works very well at popping up a window and then throwing it
  18. away after you have used it.
  19.  
  20. FWIN is implemented using a circular doubly linked list.  Therefore,
  21. you can call up any window at any time.  By the way, it uses the
  22. standard DOS and CRT units as well as my FWRITE unit.
  23.  
  24. ***
  25.  
  26. FWIN's window structure is declared like this:
  27.  
  28. type winptr = ^winrec;
  29.      winrec = record
  30.                     x,y,w,h : byte;    { The borders of the window }
  31.                     cx,cy : byte;     { The position of the cursor }
  32.                     id : byte;        { Each window has a unique ID
  33.                                         number }
  34.                     wscreen : vram_scrbuf;  { This is where the
  35.                                               saved window goes }
  36.                     up,dn : winptr; { Pointers to the windows after
  37.                                       and before this one }
  38.                     border : boolean;  { Is there a border or not? }
  39.               end;
  40.  
  41. The only visible variable in the FWIN unit is the "base" of the
  42. window list.  The current window is always one up from this.
  43.  
  44. var windowset : winptr;
  45.  
  46. ***
  47.  
  48. GetVram(var Scrn : Vram_ScrBuf);
  49.  
  50. Since FWIN often gets the whole screen, it calls this, which calls
  51. the GetVramSec procedure in FWRITE.  It is equivalent to
  52.  
  53. GetVramSec(scrn,1,1,80,25,1,1);
  54.  
  55. ***
  56.  
  57. PutVram(Scrn : Vram_ScrBuf);
  58.  
  59. This puts all of Vram_ScrBuf on the screen.  It simply calls FWRITE
  60. like this:    PutVramSec(Scrn,1,1,80,25,1,1);
  61.  
  62. It just saves some typing on your part.
  63.  
  64. ***
  65.  
  66. Bordermaker(a,b,c,d,e,f : byte) : string;
  67.  
  68. This turns bytes a,b,c,d,e,f into characters and places them in a
  69. string.  It is useful for making window borders with ASCII values
  70. above 126 or below 32.
  71.  
  72. ***
  73.  
  74. SetTextAttr(attr : byte);
  75.  
  76. This sets the current writing attribute for Turbo Pascal's Write
  77. and WriteLn.
  78.  
  79. ***
  80.  
  81. GetXY(var x,y : byte);
  82.  
  83. This calls TP5's WhereX and WhereY.  It's just a time-saver.
  84.  
  85. ***
  86.  
  87. CreateWindow(id : byte; x,y,w,h : byte; wattr,battr : byte;
  88.              st,border : string);
  89.  
  90. Wow!  What does this do?
  91.  
  92. The borders of the window are x,y,w,h.  Border is either an empty
  93. string (for no border) or the 6 chars used in the border.  This is
  94. what the characters are used for:
  95.       #1 : top left corner         #2: top right corner
  96.       #3 : bottom left corner      #4: bottom right corner
  97.       #5 : horizontal lines        #6: vertical lines
  98.  
  99. St is the string used for the "title" of the window.  It is placed
  100. centered in the top line of the border.  If there is no border, st
  101. is not used.  Batr is the attribute used for the border, and Watr
  102. is the attribute used for the main text.  While we're at it, here's
  103. at table showing the which values give which colors:
  104.  
  105. COLOR         FOREGROUND    BACKGROUND   HI-INTENSITY FOREGROUND
  106. Black             0             0             8  (Gray)
  107. Blue              1             16            9  (Light blue)
  108. Green             2             32            10 (Light green)
  109. Cyan              3             48            11 (Light cyan)
  110. Red               4             64            12 (Pink)
  111. Magenta           5             80            13 (Light magenta)
  112. Brown             6             96            14 (Yellow)
  113. White             7             112           15 (Hi-intesity white)
  114.  
  115. To get the desire attribute, add the foreground color to the
  116. background color.  For example, to get white on a black background,
  117. the attribute is 7.  For pink on a magenta background, the
  118. attribute is 92.  To make the foreground characters blink, add 128
  119. to the total.
  120.  
  121. And finally, ID is the window's unique identification number.  You
  122. use it in most of the other window routines.  If you specify the ID
  123. number of an already existing window, nothing will happen.
  124.  
  125. ***
  126.  
  127. RemoveWindow(id : byte);
  128.  
  129. This removes the window (specified by ID) from the linked list.  It
  130. doesn't, however, do anything about the image on the screen.  If you
  131. specify an ID that is non-existant, nothing will happen.  You can
  132. check to see if a window exists or not using ExistWindow.
  133.  
  134. ***
  135.  
  136. GotoWindow(id : byte);
  137.  
  138. This gets the specified window and puts it at the beginning of the
  139. linked list and updates the screen.  If a non-existant ID is called,
  140. nothing wil happen.
  141.  
  142. ***
  143.  
  144. PopWindow;
  145.  
  146. This removes the current window from the linked list and the screen.
  147. The window behind the current window now becomes the current window.
  148.  
  149. ***
  150.  
  151. ExistWindow(id : byte) : boolean;
  152.  
  153. This returns true if a window with the specified ID exists.
  154. Otherwise, it returns false.
  155.  
  156. ***
  157.  
  158. Okay, that's everything.  But I'd like to write a few extra routines
  159. here.  With createwindow, one of the problems is it's a bit hard to
  160. find out which ID numbers are already existing.  You could call
  161. existwindow from 1 until you get a false, but if you have a lot of
  162. windows, that could take a few lines that you might not want.  So
  163. let's write a function that returns the first unused ID.
  164.  
  165. function EmptyWindowID : byte;
  166. var temptr : winptr;   { We need a pointer to walk through the list }
  167.     i,j : byte;      { Variables for storing the free ID }
  168. begin
  169.      i := 0; j := 0;    { Initialize the variables }
  170.      while (i <> 0) do    { i gets set to the free ID #.  It will }
  171.      begin                { remain 0 until then. }
  172.           inc(j);    { j is the counter for possible open windows }
  173.           temptr := windowset^.up;  { temptr is pointing to the
  174.                                       current window }
  175.           while (temptr <> windowset) and (temptr^.id <> j) do
  176.           begin   { If temptr's ID = j or temptr has cirled the list, STOP }
  177.                nptr := nptr^.up;    { Go up to the next window }
  178.           end;
  179.           if nptr = windowset then i := j; { If temptr has circled, }
  180.      end;                 { that ID is free, so set i }
  181.      EmptyWindowID := i;  { give the function the result }
  182. end;
  183.  
  184.    What this does is it circles through the linked list to see if
  185. any of the windows have an ID of 1.  If none do, i is set to one.
  186. Otherwise, the same thing is done for 2 and 3 and 4 etc. until
  187. a "free" ID is found.  Then the function is set to the value of i
  188. (the free ID number).
  189.  
  190. That wasn't so hard.  Now, let's do something else.  How about this:
  191. The screen has gotten rather cluttered up, and you want to clean it
  192. up.  How do you do that?  Why don't we write a procedure to do that
  193. for us.
  194.  
  195. procedure CleanUpScreen;
  196. var temptr : winptr;
  197.     i : byte;
  198. begin
  199.      i := EmptyWindowID;
  200.      createwindow(i,1,1,80,25,7,7,'','');
  201.      temptr := windowset^.dn;
  202.      while temptr <> windowset do
  203.      begin
  204.           if temptr^.id <> i then gotowindow(temptr^.id);
  205.      end;
  206.      removewindow(i);
  207. end;
  208.  
  209.    I didn't include any comments on purpose.  I'm going to let you
  210. figure out what each line does.  That is, in my opinion, the second
  211. best way to learn how to program (assuming you know the basics).  I
  212. think the best way is just to program and program and program
  213. whatever yourself.  Most of my programming so far has been in the
  214. realm of useless.  I have scores of tiny programs that do everything
  215. from create random beeps to copy one file half as fast as DOS
  216. would.  But I have gotten lots of experience from that, and now I
  217. can quickly whip up a simple program when I need it.  One example
  218. is this:  I had a list of books read and how many pages were in
  219. each one.  I was supposed to add the pages to get the total and
  220. check to make sure there was only one entry for each book.  So
  221. in about fifteen or twenty minutes, I had written a program that
  222. did just that.  Then, I spent another fifteen minutes entering the
  223. list into the computer (the list was on paper).  So, in roughly
  224. 35 minutes, I did a job which, without any programming, would have
  225. taken maybe 40 minutes.  Big deal.  I saved 5 minutes.  But now I
  226. have the program, and it I'm most likely going to have to do that
  227. again, so overall, I could end up saving myself hours.  So now, all
  228. that experience with writing all those tiny programs is starting to
  229. pay off.
  230.  
  231.    Whoa!  I thought I was supposed to be writing documentation for
  232. FWIN!  Okay, back to that now.
  233.  
  234.    I will give you a bit of help in understanding what the
  235. CleanUpScreen procedure does.  First it calls EmptyWindowID to find
  236. an unused ID.  Then it creates a big blank window to clear the
  237. screen.  After that, it starts at the back of the list, calling
  238. each window until it arrives at the "base" to rebuild the screen.
  239. Along the way, it makes sure to skip the blank window, so the work
  240. won't be wasted.  Then, after the screen has been cleared and
  241. updated, it removes the blank window from memory, and quits.
  242.  
  243.    I also have a second windowing unit, XWIN.  XWIN is slower than
  244. FWIN is, but it doesn't have the "junk" problem.  XWIN's
  245. popwindows can be up to 10 times slower than FWIN's, but with
  246. XWIN you never need the CleanUpScreen procedure.  Actually, if
  247. FWIN calls CleanUpScreen after each popwindow to make sure the
  248. screen doesn't have any inactive windows, XWIN is much faster.  Also,
  249. FWIN takes 4 kbytes of heap for each window, whether the window is
  250. 5*4 or 80*25.  XWIN takes up a 22 bytes plus the amount of memory
  251. required to hold just the window.  Here's a formula to calculate
  252. that amount of memory:
  253.  
  254. mem_required := (window_width * window_height) * 2;
  255.  
  256. But you don't have to worry about calculating the memory; XWIN does
  257. it for you.
  258.  
  259.    I prefer using XWIN, but FWIN can still be useful.
  260.  
  261.   If you think I've left anything out, or if anything is unclear,
  262. please contact me via Compuserve, using either EasyPlex or the
  263. TP5 messages section of BPROGA.
  264.  
  265. Rex Kerr  71550,3147
  266.  
  267.                              /\ RKCP /\
  268.                              \/ RKCP \/